package miggy.ui;

import miggy.Debugger;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.Logger;

/*
//  Miggy - Java Amiga MachineCore
//  Copyright (c) 2008, Tony Headford
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
//  following conditions are met:
//
//    o  Redistributions of source code must retain the above copyright notice, this list of conditions and the
//       following disclaimer.
//    o  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
//       following disclaimer in the documentation and/or other materials provided with the distribution.
//    o  Neither the name of the Miggy Project nor the names of its contributors may be used to endorse or promote
//       products derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Revision: 21 $
*/
public class DebuggerFrame extends JFrame implements ActionListener, ItemListener
{
	private static Logger logger = Logger.getLogger(MiggyFrame.class.getName());
	private final Debugger debugger;
	private DisassemblyPanel disasmPane;
	private RegisterPanel regPane;
	private MemoryFrame memFrame;
	private boolean showMemFrame;

	public DebuggerFrame(Debugger debugger, String title)
	{
		super(title);
		this.debugger = debugger;
		create();
	}

	@Override
	public final void setVisible(boolean visible)
	{
		if(visible)
		{
			updateData();
		}

		super.setVisible(visible);

		if(showMemFrame)
			showMemoryWindow(visible);
	}

	public final void updateData()
	{
		synchronized(debugger)
		{
			regPane.updateData();
			disasmPane.updateData();
		}
	}

	private void create()
	{
		buildMenu();
		buildComponents();
		pack();
		memFrame = new MemoryFrame(debugger, "Memory");

		showMemFrame = false;
		memFrame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent we)
			{
				//ensure we're aware that the debugger is hidden
				showMemoryWindow(false);
			}
		});
	}

	private void showMemoryWindow(boolean show)
	{
		if(show != showMemFrame)
		{
			showMemFrame = show;
			memFrame.setVisible(show);
		}
	}

	private void buildComponents()
	{
		regPane = new RegisterPanel(debugger);
		add(regPane, BorderLayout.NORTH);

		disasmPane = new DisassemblyPanel(debugger);
		add(disasmPane, BorderLayout.CENTER);
	}

	private void buildMenu()
	{
		JMenuBar menuBar = new JMenuBar();

		//File Menu
		JMenu menu = new JMenu("File");
		menu.setMnemonic(KeyEvent.VK_F);
		menuBar.add(menu);

		//Open
		JMenuItem item = new JMenuItem("Open", KeyEvent.VK_O);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
		item.addActionListener(this);
		menu.add(item);

		//Close
		item = new JMenuItem("Close", KeyEvent.VK_C);
		//item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
		item.addActionListener(this);
		menu.add(item);

		menu.addSeparator();

		//Exit
		item = new JMenuItem("Exit", KeyEvent.VK_X);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK));
		item.addActionListener(this);
		menu.add(item);


		//Run Menu
		menu = new JMenu("Run");
		menu.setMnemonic(KeyEvent.VK_R);
		menuBar.add(menu);

		//Run
		item = new JMenuItem("Go", KeyEvent.VK_G);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0));
		item.addActionListener(this);
		menu.add(item);

		menu.addSeparator();

		//Step Into
		item = new JMenuItem("Step Into", KeyEvent.VK_I);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0));
		item.addActionListener(this);
		menu.add(item);

		//Step Over
		item = new JMenuItem("Step Over", KeyEvent.VK_O);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0));
		item.addActionListener(this);
		menu.add(item);

		menu.addSeparator();

		//Break
		item = new JMenuItem("Break", KeyEvent.VK_B);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0));
		item.addActionListener(this);
		menu.add(item);

		menu.addSeparator();

		//Toggle Breakpoint
		item = new JMenuItem("Toggle Breakpoint", KeyEvent.VK_P);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0));
		item.addActionListener(this);
		menu.add(item);

		//Run Menu
		menu = new JMenu("View");
		menu.setMnemonic(KeyEvent.VK_V);
		menuBar.add(menu);

		//Memory
		item = new JMenuItem("Memory", KeyEvent.VK_M);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK));
		item.addActionListener(this);
		menu.add(item);

		setJMenuBar(menuBar);
	}

	/**
	 * Invoked when an action occurs.
	 */
	public void actionPerformed(ActionEvent e)
	{
		//To change body of implemented methods use File | Settings | File Templates.
		logger.info("ActionEvent: " + e.getActionCommand());
		if(e.getActionCommand().equalsIgnoreCase("Go"))
		{
			logger.info("Starting Emu");
			debugger.start();

			//todo: disable/grey out display
		}
		else if(e.getActionCommand().equalsIgnoreCase("Break"))
		{
			logger.info("Stopping Emu");
			debugger.stop();
			//todo: reactivate display
		}
		else if(e.getActionCommand().equalsIgnoreCase("Step Into"))
		{
			logger.info("Stepping into");
			debugger.stepInto();
		}
		else if(e.getActionCommand().equalsIgnoreCase("Step Over"))
		{
			logger.info("Stepping over");
			debugger.stepOver();
		}
		else if(e.getActionCommand().equalsIgnoreCase("Toggle Breakpoint"))
		{
			logger.info("Toggle Breakpoint");
			int addr = disasmPane.getSelectedAddress();
			if(addr != -1)
			{
				if(debugger.isBreakpointHere(addr))
				{
					debugger.clrBreakpoint(addr);
				}
				else
				{
					debugger.setBreakpoint(addr);
				}
			}
		}
		else if(e.getActionCommand().equalsIgnoreCase("Memory"))
		{
			logger.info("Memory");
			showMemoryWindow(!showMemFrame);
		}
		else if(e.getActionCommand().equalsIgnoreCase("Exit"))
		{
			logger.info("Exiting from menu");
		}
	}

	/**
	 * Invoked when an item has been selected or deselected by the user.
	 * The code written for this method performs the operations
	 * that need to occur when an item is selected (or deselected).
	 */
	public void itemStateChanged(ItemEvent e)
	{
	}
}
